/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER)

#include <trace_log.h>
#include "umc_avs_dec_deblocker.h"
#include "umc_avs_sequence_header.h"
#include "umc_avs_picture_header.h"
#include "umc_avs_mb_info.h"

namespace UMC
{

// alpha table
static
Ipp8u AVS_ALPHA_TABLE[64] =
{
    0, 0, 0, 0, 0, 0, 1, 1,
    1, 1, 1, 2, 2, 2, 3, 3,
    4, 4, 5, 5, 6, 7, 8, 9,
    10,11,12,13,15,16,18,20,
    22,24,26,28,30,33,33,35,
    35,36,37,37,39,39,42,44,
    46,48,50,52,53,54,55,56,
    57,58,59,60,61,62,63,64
};

// beta table
static
Ipp8u AVS_BETA_TABLE[64] =
{
    0, 0, 0, 0, 0, 0, 1, 1,
    1, 1, 1, 1, 1, 2, 2, 2,
    2, 2, 3, 3, 3, 3, 4, 4,
    4, 4, 5, 5, 5, 5, 6, 6,
    6, 7, 7, 7, 8, 8, 8, 9,
    9,10,10,11,11,12,13,14,
    15,16,17,18,19,20,21,22,
    23,23,24,24,25,25,26,27
};

// table for scaling QP to chroma QP
static
Ipp8u AVS_QP_SCALE_CR[64] =
{
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    10,11,12,13,14,15,16,17,18,19,
    20,21,22,23,24,25,26,27,28,29,
    30,31,32,33,34,35,36,37,38,39,
    40,41,42,42,43,43,44,44,45,45,
    46,46,47,47,48,48,48,49,49,49,
    50,50,50,51,
};

// table of clipping values
Ipp8u AVS_CLIP_TABlE[64] =
{
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 2, 2,
    2, 2, 2, 2, 2, 2, 3, 3,
    3, 3, 3, 3, 3, 4, 4, 4,
    5, 5, 5, 6, 6, 6, 7, 7,
    7, 7, 8, 8, 8, 9, 9, 9
} ;

AVSDeblocker::AVSDeblocker(void)
{

} // AVSDeblocker::AVSDeblocker(void)

AVSDeblocker::~AVSDeblocker(void)
{

} // AVSDeblocker::AVSDeblocker(void)

void AVSDeblocker::PrepareNeighbours(AVS_BASE_CONTEXT *pCtx)
{
    // set the current macroblock
    m_pMbInfo = pCtx->m_pMBInfo;

    // set the pointer to the left macroblock
    m_pMbInfoLeft = NULL;

    // set the pointer to the upper macroblock
    m_pMbInfoTop = (pCtx->MbIndex > pCtx->MbFirst) ?
                   (pCtx->m_pMBInfo - pCtx->MbWidth) :
                   (NULL);

} // void AVSDeblocker::PrepareNeighbours(AVS_BASE_CONTEXT *pCtx)

void AVSDeblocker::PrepareDeblocking(void)
{
    // prepare decoding variables
    alpha_c_offset = m_debCtx.m_pPicHeader->alpha_c_offset;
    beta_offset = m_debCtx.m_pPicHeader->beta_offset;

    // prepare parameters for ipp functions
    m_lumaDebInfo.pSrcDstPlane = m_debCtx.m_pPlanes8u[0];
    m_lumaDebInfo.srcDstStep = m_debCtx.m_iPitch;
    m_lumaDebInfo.pAlpha = m_alpha;
    m_lumaDebInfo.pBeta = m_beta;
    m_lumaDebInfo.pThresholds = m_thresholds;
    m_lumaDebInfo.pBs = m_strengths;

    m_chromaDebInfo[0] = m_lumaDebInfo;
    m_chromaDebInfo[0].pSrcDstPlane = m_debCtx.m_pPlanes8u[1];

    m_chromaDebInfo[1] = m_lumaDebInfo;
    m_chromaDebInfo[1].pSrcDstPlane = m_debCtx.m_pPlanes8u[2];

} // void AVSDeblocker::PrepareDeblocking(void)

void AVSDeblocker::AdvanceNeighbours(void)
{
    // update pointer to the upper neighbour
    if (m_pMbInfoTop)
        m_pMbInfoTop += 1;

    // update pointer to the left neighbour
    m_pMbInfoLeft = m_pMbInfo;

    // update pointer to the current macroblock
    m_pMbInfo += 1;

} // void AVSDeblocker::AdvanceNeighbours(void)

void AVSDeblocker::AdvanceDeblocking(void)
{
    // update plane pointers
    if (1 == m_debCtx.m_pSeqHeader->sample_precission)
    {
        // advance luminance pointer
        m_lumaDebInfo.pSrcDstPlane += 16;

        // advance chrominance pointer
        m_chromaDebInfo[0].pSrcDstPlane += 8;
        m_chromaDebInfo[1].pSrcDstPlane += 8;
    }

} // void AVSDeblocker::AdvanceDeblocking(void)

void AVSDeblocker::DeblockIMacroBlocksRow(void)
{
    Ipp32s iMbMax = m_debCtx.MbIndex + m_debCtx.MbWidth;

    // we can use MbIndex either from decoding and reconstructing contexts
    MbIndex = m_debCtx.MbIndex;

    // initialize deblocking process
    PrepareNeighbours(&m_debCtx);
    PrepareDeblocking();

    do
    {
        WRITE_TRACE_LOG_MB_TITLE(_deb_tst, MbIndex, m_debCtx.MbWidth, m_debCtx.MbHeight, 0 == m_debCtx.m_pPicHeader->progressive_frame);

        // deblock next macroblock
        DeblockIMbVert();
        DeblockIMbHorz();

        // advance pointers and update variables
        MbIndex += 1;
        AdvanceDeblocking();
        AdvanceNeighbours();

    } while (MbIndex < iMbMax);

    // update context
    FinalizeDeblocking();

} // void AVSDeblocker::DeblockIMacroBlocksRow(void)

void AVSDeblocker::DeblockPMacroBlocksRow(void)
{
    Ipp32s iMbMax = m_debCtx.MbIndex + m_debCtx.MbWidth;

    // we can use MbIndex either from decoding and reconstructing contexts
    MbIndex = m_debCtx.MbIndex;

    // initialize deblocking process
    PrepareNeighbours(&m_debCtx);
    PrepareDeblocking();

    do
    {
        WRITE_TRACE_LOG_MB_TITLE(_deb_tst, MbIndex, m_debCtx.MbWidth, m_debCtx.MbHeight, 0 == m_debCtx.m_pPicHeader->progressive_frame);

        // deblock next macroblock
        if (I_8x8 != m_pMbInfo->MbType)
        {
            GetStrengthsForPMbVert();
            DeblockPBMbVert();
            GetStrengthsForPMbHorz();
            DeblockPBMbHorz();
        }
        else
        {
            DeblockIMbVert();
            DeblockIMbHorz();
        }

        // advance pointers and update variables
        MbIndex += 1;
        AdvanceDeblocking();
        AdvanceNeighbours();

    } while (MbIndex < iMbMax);

    // update context
    FinalizeDeblocking();

} // void AVSDeblocker::DeblockPMacroBlocksRow(void)

void AVSDeblocker::DeblockBMacroBlocksRow(void)
{
    Ipp32s iMbMax = m_debCtx.MbIndex + m_debCtx.MbWidth;

    // we can use MbIndex either from decoding and reconstructing contexts
    MbIndex = m_debCtx.MbIndex;

    // initialize deblocking process
    PrepareNeighbours(&m_debCtx);
    PrepareDeblocking();

    do
    {
        WRITE_TRACE_LOG_MB_TITLE(_deb_tst, MbIndex, m_debCtx.MbWidth, m_debCtx.MbHeight, 0 == m_debCtx.m_pPicHeader->progressive_frame);

        // deblock next macroblock
        if (I_8x8 != m_pMbInfo->MbType)
        {
            GetStrengthsForBMbVert();
            DeblockPBMbVert();
            GetStrengthsForBMbHorz();
            DeblockPBMbHorz();
        }
        else
        {
            DeblockIMbVert();
            DeblockIMbHorz();
        }

        // advance pointers and update variables
        MbIndex += 1;
        AdvanceDeblocking();
        AdvanceNeighbours();

    } while (MbIndex < iMbMax);

    // update context
    FinalizeDeblocking();

} // void AVSDeblocker::DeblockBMacroBlocksRow(void)

void AVSDeblocker::DeblockIMbVert(void)
{
    // prepare strengths array
    if (m_pMbInfoLeft)
    {
        Ipp32s averageQP;

        m_strengths[0] = 2;
        m_strengths[1] = 2;
        m_strengths[2] = 2;
        m_strengths[3] = 2;

        // prepare deblocking parameters
        averageQP = (m_pMbInfoLeft->QP + m_pMbInfo->QP + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];
    }
    else
    {
        m_strengths[0] = 0;
        m_strengths[1] = 2;
        m_strengths[2] = 0;
        m_strengths[3] = 2;
    }

    // get inner alpha & beta
    m_alpha[1] = AVS_ALPHA_TABLE[ICLIP(0, 63, m_pMbInfo->QP + alpha_c_offset)];
    m_beta[1] = AVS_BETA_TABLE[ICLIP(0, 63, m_pMbInfo->QP + beta_offset)];

    // call luminance deblocking function
    ippiFilterDeblockingLuma_VerEdge_AVS_8u_C1IR(&m_lumaDebInfo);

    // deblocking for chroma is performed on outer edge only
    if (m_pMbInfoLeft)
    {
        Ipp32s averageQP;

        // prepare deblocking parameters
        averageQP = (AVS_QP_SCALE_CR[m_pMbInfoLeft->QP] + AVS_QP_SCALE_CR[m_pMbInfo->QP] + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];

        // call luminance deblocking function
        ippiFilterDeblockingChroma_VerEdge_AVS_8u_C1IR(m_chromaDebInfo + 0);
        ippiFilterDeblockingChroma_VerEdge_AVS_8u_C1IR(m_chromaDebInfo + 1);
    }

} // void AVSDeblocker::DeblockIMbVert(void)

void AVSDeblocker::DeblockIMbHorz(void)
{
    if (m_pMbInfoTop)
    {
        Ipp32s averageQP;

        m_strengths[0] = 2;
        m_strengths[1] = 2;
        m_strengths[2] = 2;
        m_strengths[3] = 2;

        // prepare deblocking parameters
        averageQP = (m_pMbInfoTop->QP + m_pMbInfo->QP + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];
    }
    else
    {
        m_strengths[0] = 0;
        m_strengths[1] = 0;
        m_strengths[2] = 2;
        m_strengths[3] = 2;
    }

    // alpha & beta values for inner edge were prepared by
    // the vertical deblocking function

    // call luminance deblocking function
    ippiFilterDeblockingLuma_HorEdge_AVS_8u_C1IR(&m_lumaDebInfo);

    // deblocking for chroma is performed on outer edge only
    if (m_pMbInfoTop)
    {
        Ipp32s averageQP;

        // prepare deblocking parameters
        averageQP = (AVS_QP_SCALE_CR[m_pMbInfoTop->QP] + AVS_QP_SCALE_CR[m_pMbInfo->QP] + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];

        // call luminance deblocking function
        ippiFilterDeblockingChroma_HorEdge_AVS_8u_C1IR(m_chromaDebInfo + 0);
        ippiFilterDeblockingChroma_HorEdge_AVS_8u_C1IR(m_chromaDebInfo + 1);
    }

} // void AVSDeblocker::DeblockIMbHorz(void)

void AVSDeblocker::DeblockPBMbVert(void)
{
    if (m_pMbInfoLeft)
    {
        Ipp32s averageQP;

        // prepare deblocking parameters
        averageQP = (m_pMbInfoLeft->QP + m_pMbInfo->QP + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];
        m_thresholds[0] = AVS_CLIP_TABlE[ICLIP(0, 63, averageQP + alpha_c_offset)];
    }

    // get inner alpha & beta
    m_alpha[1] = AVS_ALPHA_TABLE[ICLIP(0, 63, m_pMbInfo->QP + alpha_c_offset)];
    m_beta[1] = AVS_BETA_TABLE[ICLIP(0, 63, m_pMbInfo->QP + beta_offset)];
    m_thresholds[1] = AVS_CLIP_TABlE[ICLIP(0, 63, m_pMbInfo->QP + alpha_c_offset)];

    // call luminance deblocking function
    ippiFilterDeblockingLuma_VerEdge_AVS_8u_C1IR(&m_lumaDebInfo);

    // deblocking for chroma is performed on outer edge only
    if (m_pMbInfoLeft)
    {
        Ipp32s averageQP;

        // prepare deblocking parameters
        averageQP = (AVS_QP_SCALE_CR[m_pMbInfoLeft->QP] + AVS_QP_SCALE_CR[m_pMbInfo->QP] + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];
        m_thresholds[0] = AVS_CLIP_TABlE[ICLIP(0, 63, averageQP + alpha_c_offset)];

        // call luminance deblocking function
        ippiFilterDeblockingChroma_VerEdge_AVS_8u_C1IR(m_chromaDebInfo + 0);
        ippiFilterDeblockingChroma_VerEdge_AVS_8u_C1IR(m_chromaDebInfo + 1);
    }

} // void AVSDeblocker::DeblockPBMbVert(void)

void AVSDeblocker::DeblockPBMbHorz(void)
{
    if (m_pMbInfoTop)
    {
        Ipp32s averageQP;

        // prepare deblocking parameters
        averageQP = (m_pMbInfoTop->QP + m_pMbInfo->QP + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];
        m_thresholds[0] = AVS_CLIP_TABlE[ICLIP(0, 63, averageQP + alpha_c_offset)];
    }

    // alpha & beta values for inner edge were prepared by
    // the vertical deblocking function

    // call luminance deblocking function
    ippiFilterDeblockingLuma_HorEdge_AVS_8u_C1IR(&m_lumaDebInfo);

    // deblocking for chroma is performed on outer edge only
    if (m_pMbInfoTop)
    {
        Ipp32s averageQP;

        // prepare deblocking parameters
        averageQP = (AVS_QP_SCALE_CR[m_pMbInfoTop->QP] + AVS_QP_SCALE_CR[m_pMbInfo->QP] + 1) >> 1;
        m_alpha[0] = AVS_ALPHA_TABLE[ICLIP(0, 63, averageQP + alpha_c_offset)];
        m_beta[0] = AVS_BETA_TABLE[ICLIP(0, 63, averageQP + beta_offset)];
        m_thresholds[0] = AVS_CLIP_TABlE[ICLIP(0, 63, averageQP + alpha_c_offset)];

        // call luminance deblocking function
        ippiFilterDeblockingChroma_HorEdge_AVS_8u_C1IR(m_chromaDebInfo + 0);
        ippiFilterDeblockingChroma_HorEdge_AVS_8u_C1IR(m_chromaDebInfo + 1);
    }

} // void AVSDeblocker::DeblockPBMbHorz(void)

void AVSDeblocker::GetStrengthsForPMbVert(void)
{
    Ipp32u i;

    // set deblocking strenghts for outer edge
    if (m_pMbInfoLeft)
    {
        if (I_8x8 != m_pMbInfoLeft->MbType)
        {
            for (i = 0; i <= 2; i += 2)
            {
                // if blocks use different reference pictures
                if (m_pMbInfoLeft->refIdx[AVS_FORWARD][i + 1] !=
                    m_pMbInfo->refIdx[AVS_FORWARD][i])
                {
                    m_strengths[i] = 1;
                }
                // if difference between motion vectors is greater than one PIXEL
                else
                {
                    AVSMVector vecPrev, vecCurr;

                    vecPrev = m_pMbInfoLeft->mv[AVS_FORWARD][i + 1];
                    vecCurr = m_pMbInfo->mv[AVS_FORWARD][i];

                    if ((4 <= abs(vecPrev.vector.x - vecCurr.vector.x)) ||
                        (4 <= abs(vecPrev.vector.y - vecCurr.vector.y)))
                    {
                        m_strengths[i] = 1;
                    }
                    else
                    {
                        m_strengths[i] = 0;
                    }
                }
            }
        }
        // neighbouring MB has intra type
        else
        {
            m_strengths[0] = 2;
            m_strengths[2] = 2;
        }
    }
    else
    {
        m_strengths[0] = 0;
        m_strengths[2] = 0;
    }

    // set deblocking strenghts for inner edge
    for (i = 1; i <= 3; i += 2)
    {
        // if blocks use different reference pictures
        if (m_pMbInfo->refIdx[AVS_FORWARD][i - 1] !=
            m_pMbInfo->refIdx[AVS_FORWARD][i])
        {
            m_strengths[i] = 1;
        }
        // if difference between motion vectors is greater than one PIXEL
        else
        {
            AVSMVector vecPrev, vecCurr;

            vecPrev = m_pMbInfo->mv[AVS_FORWARD][i - 1];
            vecCurr = m_pMbInfo->mv[AVS_FORWARD][i];

            if ((4 <= abs(vecPrev.vector.x - vecCurr.vector.x)) ||
                (4 <= abs(vecPrev.vector.y - vecCurr.vector.y)))
            {
                m_strengths[i] = 1;
            }
            else
            {
                m_strengths[i] = 0;
            }
        }
    }

} // void AVSDeblocker::GetStrengthsForPMbVert(void)

void AVSDeblocker::GetStrengthsForPMbHorz(void)
{
    Ipp32u i;

    // set deblocking strenghts for outer edge
    if (m_pMbInfoTop)
    {
        if (I_8x8 != m_pMbInfoTop->MbType)
        {
            for (i = 0; i <= 1; i += 1)
            {
                // if blocks use different reference pictures
                if (m_pMbInfoTop->refIdx[AVS_FORWARD][i + 2] !=
                    m_pMbInfo->refIdx[AVS_FORWARD][i])
                {
                    m_strengths[i] = 1;
                }
                // if difference between motion vectors is greater than one PIXEL
                else
                {
                    AVSMVector vecPrev, vecCurr;

                    vecPrev = m_pMbInfoTop->mv[AVS_FORWARD][i + 2];
                    vecCurr = m_pMbInfo->mv[AVS_FORWARD][i];

                    if ((4 <= abs(vecPrev.vector.x - vecCurr.vector.x)) ||
                        (4 <= abs(vecPrev.vector.y - vecCurr.vector.y)))
                    {
                        m_strengths[i] = 1;
                    }
                    else
                    {
                        m_strengths[i] = 0;
                    }
                }
            }
        }
        // neighbouring MB has intra type
        else
        {
            m_strengths[0] = 2;
            m_strengths[1] = 2;
        }
    }
    else
    {
        m_strengths[0] = 0;
        m_strengths[1] = 0;
    }

    // set deblocking strenghts for inner edge
    for (i = 2; i <= 3; i += 1)
    {
        // if blocks use different reference pictures
        if (m_pMbInfo->refIdx[AVS_FORWARD][i - 2] !=
            m_pMbInfo->refIdx[AVS_FORWARD][i])
        {
            m_strengths[i] = 1;
        }
        // if difference between motion vectors is greater than one PIXEL
        else
        {
            AVSMVector vecPrev, vecCurr;

            vecPrev = m_pMbInfo->mv[AVS_FORWARD][i - 2];
            vecCurr = m_pMbInfo->mv[AVS_FORWARD][i];

            if ((4 <= abs(vecPrev.vector.x - vecCurr.vector.x)) ||
                (4 <= abs(vecPrev.vector.y - vecCurr.vector.y)))
            {
                m_strengths[i] = 1;
            }
            else
            {
                m_strengths[i] = 0;
            }
        }
    }

} // void AVSDeblocker::GetStrengthsForPMbHorz(void)

void AVSDeblocker::GetStrengthsForBMbVert(void)
{
    Ipp32u i;

    // set deblocking strenghts for outer edge
    if (m_pMbInfoLeft)
    {
        if (I_8x8 != m_pMbInfoLeft->MbType)
        {
            for (i = 0; i <= 2; i += 2)
            {
                // if blocks use different reference pictures
                if ((m_pMbInfoLeft->predType[i + 1] != m_pMbInfo->predType[i]) ||
                    (m_pMbInfoLeft->refIdx[AVS_FORWARD][i + 1] != m_pMbInfo->refIdx[AVS_FORWARD][i]) ||
                    (m_pMbInfoLeft->refIdx[AVS_BACKWARD][i + 1] != m_pMbInfo->refIdx[AVS_BACKWARD][i]))
                {
                    m_strengths[i] = 1;
                }
                // if difference between motion vectors is greater than one PIXEL
                else
                {
                    AVSMVector vecPrevFwd, vecCurrFwd;
                    AVSMVector vecPrevBwd, vecCurrBwd;

                    vecPrevFwd = m_pMbInfoLeft->mv[AVS_FORWARD][i + 1];
                    vecCurrFwd = m_pMbInfo->mv[AVS_FORWARD][i];
                    vecPrevBwd = m_pMbInfoLeft->mv[AVS_BACKWARD][i + 1];
                    vecCurrBwd = m_pMbInfo->mv[AVS_BACKWARD][i];

                    if ((4 <= abs(vecPrevFwd.vector.x - vecCurrFwd.vector.x)) ||
                        (4 <= abs(vecPrevFwd.vector.y - vecCurrFwd.vector.y)) ||
                        (4 <= abs(vecPrevBwd.vector.x - vecCurrBwd.vector.x)) ||
                        (4 <= abs(vecPrevBwd.vector.y - vecCurrBwd.vector.y)))
                    {
                        m_strengths[i] = 1;
                    }
                    else
                    {
                        m_strengths[i] = 0;
                    }
                }
            }
        }
        // neighbouring MB has intra type
        else
        {
            m_strengths[0] = 2;
            m_strengths[2] = 2;
        }
    }
    else
    {
        m_strengths[0] = 0;
        m_strengths[2] = 0;
    }

    // set deblocking strenghts for inner edge
    for (i = 1; i <= 3; i += 2)
    {
        // if blocks use different reference pictures
        if ((m_pMbInfo->predType[i - 1] != m_pMbInfo->predType[i]) ||
            (m_pMbInfo->refIdx[AVS_FORWARD][i - 1] != m_pMbInfo->refIdx[AVS_FORWARD][i]) ||
            (m_pMbInfo->refIdx[AVS_BACKWARD][i - 1] != m_pMbInfo->refIdx[AVS_BACKWARD][i]))
        {
            m_strengths[i] = 1;
        }
        // if difference between motion vectors is greater than one PIXEL
        else
        {
            AVSMVector vecPrevFwd, vecCurrFwd;
            AVSMVector vecPrevBwd, vecCurrBwd;

            vecPrevFwd = m_pMbInfo->mv[AVS_FORWARD][i - 1];
            vecCurrFwd = m_pMbInfo->mv[AVS_FORWARD][i];
            vecPrevBwd = m_pMbInfo->mv[AVS_BACKWARD][i - 1];
            vecCurrBwd = m_pMbInfo->mv[AVS_BACKWARD][i];

            if ((4 <= abs(vecPrevFwd.vector.x - vecCurrFwd.vector.x)) ||
                (4 <= abs(vecPrevFwd.vector.y - vecCurrFwd.vector.y)) ||
                (4 <= abs(vecPrevBwd.vector.x - vecCurrBwd.vector.x)) ||
                (4 <= abs(vecPrevBwd.vector.y - vecCurrBwd.vector.y)))
            {
                m_strengths[i] = 1;
            }
            else
            {
                m_strengths[i] = 0;
            }
        }
    }

} // void AVSDeblocker::GetStrengthsForBMbVert(void)

void AVSDeblocker::GetStrengthsForBMbHorz(void)
{
    Ipp32u i;

    // set deblocking strenghts for outer edge
    if (m_pMbInfoTop)
    {
        if (I_8x8 != m_pMbInfoTop->MbType)
        {
            for (i = 0; i <= 1; i += 1)
            {
                // if blocks use different reference pictures
                if ((m_pMbInfoTop->predType[i + 2] != m_pMbInfo->predType[i]) ||
                    (m_pMbInfoTop->refIdx[AVS_FORWARD][i + 2] != m_pMbInfo->refIdx[AVS_FORWARD][i]) ||
                    (m_pMbInfoTop->refIdx[AVS_BACKWARD][i + 2] != m_pMbInfo->refIdx[AVS_BACKWARD][i]))
                {
                    m_strengths[i] = 1;
                }
                // if difference between motion vectors is greater than one PIXEL
                else
                {
                    AVSMVector vecPrevFwd, vecCurrFwd;
                    AVSMVector vecPrevBwd, vecCurrBwd;

                    vecPrevFwd = m_pMbInfoTop->mv[AVS_FORWARD][i + 2];
                    vecCurrFwd = m_pMbInfo->mv[AVS_FORWARD][i];
                    vecPrevBwd = m_pMbInfoTop->mv[AVS_BACKWARD][i + 2];
                    vecCurrBwd = m_pMbInfo->mv[AVS_BACKWARD][i];

                    if ((4 <= abs(vecPrevFwd.vector.x - vecCurrFwd.vector.x)) ||
                        (4 <= abs(vecPrevFwd.vector.y - vecCurrFwd.vector.y)) ||
                        (4 <= abs(vecPrevBwd.vector.x - vecCurrBwd.vector.x)) ||
                        (4 <= abs(vecPrevBwd.vector.y - vecCurrBwd.vector.y)))
                    {
                        m_strengths[i] = 1;
                    }
                    else
                    {
                        m_strengths[i] = 0;
                    }
                }
            }
        }
        // neighbouring MB has intra type
        else
        {
            m_strengths[0] = 2;
            m_strengths[1] = 2;
        }
    }
    else
    {
        m_strengths[0] = 0;
        m_strengths[1] = 0;
    }

    // set deblocking strenghts for inner edge
    for (i = 2; i <= 3; i += 1)
    {
        // if blocks use different reference pictures
        if ((m_pMbInfo->predType[i - 2] != m_pMbInfo->predType[i]) ||
            (m_pMbInfo->refIdx[AVS_FORWARD][i - 2] != m_pMbInfo->refIdx[AVS_FORWARD][i]) ||
            (m_pMbInfo->refIdx[AVS_BACKWARD][i - 2] != m_pMbInfo->refIdx[AVS_BACKWARD][i]))
        {
            m_strengths[i] = 1;
        }
        // if difference between motion vectors is greater than one PIXEL
        else
        {
            AVSMVector vecPrevFwd, vecCurrFwd;
            AVSMVector vecPrevBwd, vecCurrBwd;

            vecPrevFwd = m_pMbInfo->mv[AVS_FORWARD][i - 2];
            vecCurrFwd = m_pMbInfo->mv[AVS_FORWARD][i];
            vecPrevBwd = m_pMbInfo->mv[AVS_BACKWARD][i - 2];
            vecCurrBwd = m_pMbInfo->mv[AVS_BACKWARD][i];

            if ((4 <= abs(vecPrevFwd.vector.x - vecCurrFwd.vector.x)) ||
                (4 <= abs(vecPrevFwd.vector.y - vecCurrFwd.vector.y)) ||
                (4 <= abs(vecPrevBwd.vector.x - vecCurrBwd.vector.x)) ||
                (4 <= abs(vecPrevBwd.vector.y - vecCurrBwd.vector.y)))
            {
                m_strengths[i] = 1;
            }
            else
            {
                m_strengths[i] = 0;
            }
        }
    }

} // void AVSDeblocker::GetStrengthsForBMbHorz(void)

void AVSDeblocker::FinalizeDeblocking(void)
{
    // update variables
    m_debCtx.MbIndex += m_debCtx.MbWidth;
    m_debCtx.m_pMBInfo += m_debCtx.MbWidth;
    m_debCtx.MbX = 0;
    m_debCtx.MbY = m_debCtx.MbY + 1;

    // update pointers to the video planes
    if (1 == m_debCtx.m_pSeqHeader->sample_precission)
    {
        Ipp32s iPitch = m_debCtx.m_iPitch;

        m_debCtx.m_pPlanes8u[0] += iPitch * 16;
        if (AVS_CHROMA_420_FORMAT == m_debCtx.m_pSeqHeader->chroma_format)
        {
            m_debCtx.m_pPlanes8u[1] += iPitch * 8;
            m_debCtx.m_pPlanes8u[2] += iPitch * 8;
        }
        else
        {
            m_debCtx.m_pPlanes8u[1] += iPitch * 16;
            m_debCtx.m_pPlanes8u[2] += iPitch * 16;
        }
    }

} // void AVSDeblocker::FinalizeDeblocking(void)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_DECODER)
